/*
 * Copyright 2019 xiaomaoguai.com All right reserved. This software is the
 * confidential and proprietary information of xiaomaoguai.com ("Confidential
 * Information"). You shall not disclose such Confidential Information and shall
 * use it only in accordance with the terms of the license agreement you entered
 * into with xiaomaoguai.com.
 */

package com.xiaomaoguai.core.next.tddl.config;

import java.util.Optional;

import javax.sql.DataSource;

import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.support.TransactionTemplate;

import com.alibaba.fastjson.JSON;
import com.taobao.tddl.client.jdbc.TDataSource;
import com.taobao.tddl.client.sequence.impl.GroupSequenceDao;
import com.xiaomaoguai.core.next.tddl.constants.TddlConstants;
import com.xiaomaoguai.core.next.tddl.sequence.TddlSequenceUtils;

import app.myoss.cloud.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration;
import app.myoss.cloud.mybatis.table.Sequence;
import app.myoss.cloud.mybatis.table.TableMetaObject;
import lombok.extern.slf4j.Slf4j;

/**
 * TDDL 自动配置，支持单个数据库
 *
 * @author chenyao
 * @since 2018年5月17日 下午1:37:48
 */
@AutoConfigureBefore(MybatisAutoConfiguration.class)
@Slf4j
@EnableConfigurationProperties({ TddlProperties.class })
@ConditionalOnProperty(prefix = TddlConstants.CONFIG_PREFIX, value = "enabled", matchIfMissing = false)
@Configuration
public class TddlAutoConfiguration {
    private TddlProperties properties;

    /**
     * 初始化 TDDL 自动配置
     *
     * @param properties TDDL 属性配置
     */
    public TddlAutoConfiguration(TddlProperties properties) {
        this.properties = properties;
        if (log.isInfoEnabled()) {
            log.info("init TDDL auto configuration, properties: {}", JSON.toJSONString(properties));
        }
    }

    /**
     * 初始化 TDDL 数据源
     *
     * @return TDDL 数据源
     */
    @Primary
    @Bean(initMethod = "init", name = "dataSource")
    public TDataSource dataSource() {
        TDataSource dataSource = new TDataSource();
        dataSource.setAppName(this.properties.getAppName());
        dataSource.setDynamicRule(true);
        return dataSource;
    }

    /**
     * 初始化数据源事务管理者
     *
     * @param dataSource 数据源
     * @return 数据源事务管理者
     */
    @ConditionalOnMissingBean
    @Bean
    public DataSourceTransactionManager transactionManager(DataSource dataSource) {
        log.info("create default [DataSourceTransactionManager]");
        DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();
        dataSourceTransactionManager.setDataSource(dataSource);
        return dataSourceTransactionManager;
    }

    /**
     * 初始化事务管理模版
     *
     * @param transactionManager 数据源事务管理者
     * @return 事务管理模版
     */
    @ConditionalOnMissingBean
    @Bean
    public TransactionTemplate transactionTemplate(DataSourceTransactionManager transactionManager) {
        log.info("create default [TransactionTemplate]");
        TransactionTemplate template = new TransactionTemplate();
        template.setTransactionManager(transactionManager);
        return template;
    }

    /**
     * 初始化默认的 TDDL GroupSequenceDao 实例对象
     *
     * @return TDDL GroupSequenceDao 实例对象
     */
    @Primary
    @ConditionalOnProperty(prefix = TddlConstants.CONFIG_PREFIX, value = "group-name", matchIfMissing = false)
    @ConditionalOnMissingBean
    @Bean(initMethod = "init")
    public GroupSequenceDao sequenceDao() {
        return TddlSequenceUtils.buildSequenceDao(this.properties, false);
    }

    /**
     * 初始化表的 TDDL sequence，用于生成主键id
     *
     * @param sequenceDao TDDL GroupSequenceDao 实例对象
     * @param applicationContext Spring Application Context
     * @return 空对象
     */
    @ConditionalOnClass({ Sequence.class, TableMetaObject.class })
    @ConditionalOnBean(GroupSequenceDao.class)
    @ConditionalOnMissingBean(name = "initTddlSequence")
    @Bean
    public Optional<Sequence> initTddlSequence(GroupSequenceDao sequenceDao, ApplicationContext applicationContext) {
        TddlSequenceUtils.initTddlSequence(TableMetaObject.getSequenceBeanMap().values(), sequenceDao,
                applicationContext);
        return Optional.empty();
    }
}
